package com.luo.d3s.ec.domain.order.model;

import com.luo.d3s.core.domain.model.AggregateRoot;
import com.luo.d3s.core.util.validation.Validates;
import com.luo.d3s.share.model.BizId;
import com.luo.d3s.share.model.Price;

import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;

/**
 * 订单
 *
 * @author luohq
 * @date 2022-11-27 16:08
 */
public class Order implements AggregateRoot<BizId> {
    /**
     * 订单ID
     */
    @NotNull
    private BizId id;

    /**
     * 订单商品列表
     */
    @NotEmpty
    private List<OrderGoods> orderGoods;

    /**
     * 订单价格
     */
    @NotNull
    private Price orderPrice;

    /**
     * 收货地址
     */
    @NotNull
    private ReceiveAddress receiveAddress;

    /**
     * 订单状态
     */
    @NotNull
    private OrderStatus orderStatus;

    /**
     * 创建时间
     */
    private LocalDateTime createTime;

    /**
     * 支付时间
     */
    private LocalDateTime payTime;

    /**
     * 快递单号
     */
    private ExpressCode expressCode;

    /**
     * 配送时间
     */
    private LocalDateTime deliverTime;

    /**
     * 完成时间
     */
    private LocalDateTime completeTime;

    /**
     * 取消时间
     */
    private LocalDateTime cancelTime;

    /**
     * 更新时间
     */
    private LocalDateTime updateTime;


    Order() {
    }

    /**
     * 初始创建订单信息
     *
     * @param id             订单ID
     * @param orderGoods     订单商品
     * @param orderPrice     订单总价
     * @param receiveAddress 收货地址
     */
    Order(BizId id, Price orderPrice, ReceiveAddress receiveAddress, List<OrderGoods> orderGoods) {
        this.id = id;
        this.orderPrice = orderPrice;
        this.receiveAddress = receiveAddress;
        this.orderGoods = orderGoods;
        this.orderStatus = OrderStatus.CREATED;
        this.createTime = LocalDateTime.now();
        this.validateSelf();
    }

    public Order(BizId id, List<OrderGoods> orderGoods, Price orderPrice, ReceiveAddress receiveAddress, OrderStatus orderStatus,
                 LocalDateTime createTime, LocalDateTime payTime, ExpressCode expressCode, LocalDateTime deliverTime,
                 LocalDateTime completeTime, LocalDateTime cancelTime, LocalDateTime updateTime) {
        this.id = id;
        this.orderGoods = orderGoods;
        this.orderPrice = orderPrice;
        this.receiveAddress = receiveAddress;
        this.orderStatus = orderStatus;
        this.createTime = createTime;
        this.payTime = payTime;
        this.expressCode = expressCode;
        this.deliverTime = deliverTime;
        this.completeTime = completeTime;
        this.cancelTime = cancelTime;
        this.updateTime = updateTime;
    }

    /**
     * 支付订单
     */
    public void payOrder() {
        Validates.isTrue(OrderStatus.CREATED.equals(this.getOrderStatus()), "order status is not CREATED");
        this.orderStatus = OrderStatus.PAID;
        this.payTime = this.updateTime = LocalDateTime.now();
    }

    /**
     * 发货订单
     *
     * @param expressCode 快递单号
     * @param deliverTime 发货时间
     */
    public void deliverOrder(ExpressCode expressCode, LocalDateTime deliverTime) {
        Validates.isTrue(OrderStatus.PAID.equals(this.getOrderStatus()), "order status is not PAID");
        this.orderStatus = OrderStatus.DELIVERED;
        this.expressCode = expressCode;
        this.deliverTime = deliverTime;
        this.updateTime = LocalDateTime.now();
    }

    /**
     * 完成订单
     */
    public void completeOrder() {
        Validates.isTrue(OrderStatus.DELIVERED.equals(this.getOrderStatus()), "order status is not DELIVERED");
        this.orderStatus = OrderStatus.COMPLETED;
        this.completeTime = this.updateTime = LocalDateTime.now();
    }

    /**
     * 取消订单
     */
    public void cancelOrder() {
        this.orderStatus = OrderStatus.CANCELED;
        this.cancelTime = this.updateTime = LocalDateTime.now();
    }

    @Override
    public BizId getId() {
        return id;
    }

    public List<OrderGoods> getOrderGoods() {
        return orderGoods;
    }

    public Price getOrderPrice() {
        return orderPrice;
    }

    public ReceiveAddress getReceiveAddress() {
        return receiveAddress;
    }

    public OrderStatus getOrderStatus() {
        return orderStatus;
    }

    public LocalDateTime getCreateTime() {
        return createTime;
    }

    public LocalDateTime getPayTime() {
        return payTime;
    }

    public ExpressCode getExpressCode() {
        return expressCode;
    }

    public LocalDateTime getDeliverTime() {
        return deliverTime;
    }

    public LocalDateTime getCompleteTime() {
        return completeTime;
    }

    public LocalDateTime getCancelTime() {
        return cancelTime;
    }

    public LocalDateTime getUpdateTime() {
        return updateTime;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        Order order = (Order) o;
        return Objects.equals(id, order.id);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }

    @Override
    public String toString() {
        return "Order{" +
                "id=" + id +
                ", orderGoods=" + orderGoods +
                ", orderPrice=" + orderPrice +
                ", receiveAddress=" + receiveAddress +
                ", orderStatus=" + orderStatus +
                ", createTime=" + createTime +
                ", payTime=" + payTime +
                ", expressCode=" + expressCode +
                ", deliverTime=" + deliverTime +
                ", completeTime=" + completeTime +
                ", cancelTime=" + cancelTime +
                ", updateTime=" + updateTime +
                '}';
    }
}
